﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using ParsecClient.ParsecRaidWebService;

namespace ParsecClient.Classes
{
    public static class ParsecRaidServiceHelpers
    {
        public static string StringifyServiceCommand(string raidGroup, string raidPassword, string adminPassword)
        {
            return raidGroup + "|" + raidPassword + "|" + adminPassword;
        }
        public static string Stringify(this ParsecRaidResponse r, bool compress)
        {
            string s = r.MinimumPollingRate.ToString() + "|" + r.ErrorMessage + Environment.NewLine + string.Join(Environment.NewLine, r.Users.Select(x => x.Stringify()).ToArray());
            if (!compress)
                return s;
            else
            {
                return CompressString(s);
            }
        }
        public static ParsecRaidResponse DeStringifyResponse(string ds, bool isCompressed)
        {
            ParsecRaidResponse rval = new ParsecRaidResponse()
                {
                    MinimumPollingRate =3000,
                    Users = new List<ParsecRaidUser>()
                };
            int lineIndex = 0;
            string s = ds;
            if (isCompressed)
            {
                s = DecompressString(s, true);
            }
            using (StringReader reader = new StringReader(s))
            {
                while (true)
                {
                    string line = reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }
                    else if (lineIndex == 0)
                    {
                        string[] lar = line.Split('|');
                        if (lar.Length == 2)
                        {
                            string mpr = lar[0] ?? "0";
                            int mpri = 0;
                            if (int.TryParse(mpr, out mpri) && mpri > 0)
                                rval.MinimumPollingRate = mpri;
                            rval.ErrorMessage = lar[1];
                        }
                    }
                    else
                    {
                        rval.Users.Add(DeStringifyUser(line));
                    }
                    lineIndex++;
                }
            }

            return rval;
        }
        public static string Stringify(this ParsecRaidUser u)
        {
            string[] ar = new string[] { 
                u.RaidUserId.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.CharacterName,
                u.RaidGroupId.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.LastConnectDate.ToString("o",System.Globalization.CultureInfo.InvariantCulture),
                u.IsConnected ? "1" : "0",
                u.DamageOut.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.DamageIn.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.HealOut.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.EffectiveHealOut.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.HealIn.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.Threat.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.RaidEncounterId.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.RaidEncounterMode.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.RaidEncounterPlayers.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.CombatTicks.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.CombatStart.HasValue ? u.CombatStart.Value.ToString("o",System.Globalization.CultureInfo.InvariantCulture): "",
                u.CombatEnd.HasValue ? u.CombatEnd.Value.ToString("o",System.Globalization.CultureInfo.InvariantCulture) : "",
                u.LastCombatUpdate.HasValue ? u.LastCombatUpdate.Value.ToString("o",System.Globalization.CultureInfo.InvariantCulture) : "",
                u.ThreatList,
                u.ParsecVersion,
                u.AbsorbShieldsCast.ToString(System.Globalization.CultureInfo.InvariantCulture),
                u.AbsorbShieldValue.ToString(System.Globalization.CultureInfo.InvariantCulture)
            };
            return string.Join("|", ar);
        }
        public static ParsecRaidUser DeStringifyUser(string s)
        {
            ParsecRaidUser u = new ParsecRaidUser();
            try
            {
                String[] a = s.Split('|');
                u.RaidUserId = Convert.ToInt32(a[0], System.Globalization.CultureInfo.InvariantCulture);
                u.CharacterName = a[1];
                u.RaidGroupId = Convert.ToInt32(a[2], System.Globalization.CultureInfo.InvariantCulture);
                u.LastConnectDate = Convert.ToDateTime(a[3], System.Globalization.CultureInfo.InvariantCulture);
                u.IsConnected = Convert.ToInt32(a[4]) == 1 ? true : false;
                u.DamageOut = Convert.ToInt64(a[5], System.Globalization.CultureInfo.InvariantCulture);
                u.DamageIn = Convert.ToInt64(a[6], System.Globalization.CultureInfo.InvariantCulture);
                u.HealOut = Convert.ToInt64(a[7], System.Globalization.CultureInfo.InvariantCulture);
                u.EffectiveHealOut = Convert.ToInt64(a[8], System.Globalization.CultureInfo.InvariantCulture);
                u.HealIn = Convert.ToInt64(a[9], System.Globalization.CultureInfo.InvariantCulture);
                u.Threat = Convert.ToInt64(a[10], System.Globalization.CultureInfo.InvariantCulture);
                u.RaidEncounterId = Convert.ToInt32(a[11], System.Globalization.CultureInfo.InvariantCulture);
                u.RaidEncounterMode = Convert.ToInt32(a[12], System.Globalization.CultureInfo.InvariantCulture);
                u.RaidEncounterPlayers = Convert.ToInt32(a[13], System.Globalization.CultureInfo.InvariantCulture);
                u.CombatTicks = Convert.ToInt64(a[14], System.Globalization.CultureInfo.InvariantCulture);
                u.CombatStart = string.IsNullOrEmpty(a[15]) ? (DateTime?)null : Convert.ToDateTime(a[15], System.Globalization.CultureInfo.InvariantCulture);
                u.CombatEnd = string.IsNullOrEmpty(a[16]) ? (DateTime?)null : Convert.ToDateTime(a[16], System.Globalization.CultureInfo.InvariantCulture);
                u.LastCombatUpdate = string.IsNullOrEmpty(a[17]) ? (DateTime?)null : Convert.ToDateTime(a[17], System.Globalization.CultureInfo.InvariantCulture);
                u.ThreatList = string.IsNullOrEmpty(a[18]) ? null : a[18];
                u.ParsecVersion = string.IsNullOrEmpty(a[19]) ? null : a[19];
                u.AbsorbShieldsCast = Convert.ToInt32(a[20], System.Globalization.CultureInfo.InvariantCulture);
                u.AbsorbShieldValue = Convert.ToDouble(a[21], System.Globalization.CultureInfo.InvariantCulture);
            }
            catch
            {
                //do nothing
            }
            return u;
        }
        public static string StringifyParameters(ParsecRaidParameters r, bool compress)
        {
            string s = r.RaidGroup.ToString(System.Globalization.CultureInfo.InvariantCulture) + "|" + r.RaidPassword + "|" + (r.Statistics ?? new ParsecRaidUser()).Stringify();
            if (!compress)
                return s;
            else
            {
                return CompressString(s);
            }
        }
        public static ParsecRaidParameters DeStringifyParameters(string ds, bool isCompressed)
        {
            ParsecRaidParameters rval = new ParsecRaidParameters();
            string s = ds;
            if (isCompressed)
            {
                s = DecompressString(s, true);
            }
            string[] lar = s.Split('|');
            if (s.Length > 2)
            {
                rval.RaidGroup = lar[0];
                rval.RaidPassword = lar[1];
                string u = string.Join("|", lar.Skip(2).ToArray());
                rval.Statistics = DeStringifyUser(u);
            }
            return rval;
        }
        public static string CompressString(string obj)
        {
            using (MemoryStream msCompressed = new MemoryStream())
            using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress))
            using (MemoryStream msDecompressed = new MemoryStream())
            {
                byte[] byteArray = System.Text.Encoding.Unicode.GetBytes(obj.ToCharArray());
                gZipStream.Write(byteArray, 0, byteArray.Length);
                gZipStream.Close();
                return System.Convert.ToBase64String(msCompressed.ToArray());
            }
        }
        public static string DecompressString(string obj, bool suppressFailureException)
        {
            try
            {
                byte[] byteArray = System.Convert.FromBase64String(obj);
                using (MemoryStream msCompressed = new MemoryStream(byteArray))
                using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Decompress))
                {
                    int size = 4096;
                    byte[] buffer = new byte[size];
                    using (MemoryStream msDecompressed = new MemoryStream())
                    {
                        int count = 0;
                        do
                        {
                            count = gZipStream.Read(buffer, 0, size);
                            if (count > 0)
                            {
                                msDecompressed.Write(buffer, 0, count);
                            }
                        }
                        while (count > 0);
                        byte[] result = msDecompressed.ToArray();
                        return System.Text.Encoding.Unicode.GetString(result);
                    }
                }
            }
            catch
            {
                if (suppressFailureException)
                    return null;
                else
                    throw;
            }
        }
    }
}
